home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Amiga Format CD 24
/
Amiga Format AFCD24 (Feb 1998, Issue 108).iso
/
-in_the_mag-
/
emulation
/
amiga
/
uae-0.7.0b2
/
src
/
fpp.c
< prev
next >
Wrap
C/C++ Source or Header
|
1998-01-20
|
30KB
|
1,345 lines
/*
* UAE - The Un*x Amiga Emulator
*
* MC68881 emulation
*
* Copyright 1996 Herman ten Brugge
*/
#include <math.h>
#include "sysconfig.h"
#include "sysdeps.h"
#include "config.h"
#include "options.h"
#include "memory.h"
#include "custom.h"
#include "readcpu.h"
#include "newcpu.h"
#include "ersatz.h"
#if CPU_LEVEL >= 3
#define DEBUG_FPP 0
/* single : S 8*E 23*F */
/* double : S 11*E 52*F */
/* extended : S 15*E 64*F */
/* E = 0 & F = 0 -> 0 */
/* E = MAX & F = 0 -> Infin */
/* E = MAX & F # 0 -> NotANumber */
/* E = biased by 127 (single) ,1023 (double) ,16383 (extended) */
static __inline__ double to_single(uae_u32 value)
{
double frac;
if ((value & 0x7fffffff) == 0)
return (0.0);
frac = (double) ((value & 0x7fffff) | 0x800000) / 8388608.0;
if (value & 0x80000000)
frac = -frac;
return (ldexp(frac, ((value >> 23) & 0xff) - 127));
}
static __inline__ uae_u32
from_single(double src)
{
int expon;
uae_u32 tmp;
double frac;
if (src == 0.0)
return 0;
if (src < 0) {
tmp = 0x80000000;
src = -src;
} else {
tmp = 0;
}
frac = frexp(src, &expon);
frac += 0.5 / 16777216.0;
if (frac >= 1.0) {
frac /= 2.0;
expon++;
}
return (tmp | (((expon + 127 - 1) & 0xff) << 23) |
(((int) (frac * 16777216.0)) & 0x7fffff));
}
static __inline__ double to_exten(uae_u32 wrd1, uae_u32 wrd2, uae_u32 wrd3)
{
double frac;
if ((wrd1 & 0x7fff0000) == 0 && wrd2 == 0 && wrd3 == 0)
return 0.0;
frac = (double) wrd2 / 2147483648.0 +
(double) wrd3 / 9223372036854775808.0;
if (wrd1 & 0x80000000)
frac = -frac;
return ldexp(frac, ((wrd1 >> 16) & 0x7fff) - 16383);
}
static __inline__ void from_exten(double src, uae_u32 * wrd1, uae_u32 * wrd2, uae_u32 * wrd3)
{
int expon;
double frac;
if (src == 0.0) {
*wrd1 = 0;
*wrd2 = 0;
*wrd3 = 0;
return;
}
if (src < 0) {
*wrd1 = 0x80000000;
src = -src;
} else {
*wrd1 = 0;
}
frac = frexp(src, &expon);
frac += 0.5 / 18446744073709551616.0;
if (frac >= 1.0) {
frac /= 2.0;
expon++;
}
*wrd1 |= (((expon + 16383 - 1) & 0x7fff) << 16);
*wrd2 = (uae_u32) (frac * 4294967296.0);
*wrd3 = (uae_u32) (frac * 18446744073709551616.0 - *wrd2 * 4294967296.0);
}
static __inline__ double to_double(uae_u32 wrd1, uae_u32 wrd2)
{
double frac;
if ((wrd1 & 0x7fffffff) == 0 && wrd2 == 0)
return 0.0;
frac = (double) ((wrd1 & 0xfffff) | 0x100000) / 1048576.0 +
(double) wrd2 / 4503599627370496.0;
if (wrd1 & 0x80000000)
frac = -frac;
return ldexp(frac, ((wrd1 >> 20) & 0x7ff) - 1023);
}
static __inline__ void from_double(double src, uae_u32 * wrd1, uae_u32 * wrd2)
{
int expon;
int tmp;
double frac;
if (src == 0.0) {
*wrd1 = 0;
*wrd2 = 0;
return;
}
if (src < 0) {
*wrd1 = 0x80000000;
src = -src;
} else {
*wrd1 = 0;
}
frac = frexp(src, &expon);
frac += 0.5 / 9007199254740992.0;
if (frac >= 1.0) {
frac /= 2.0;
expon++;
}
tmp = (uae_u32) (frac * 2097152.0);
*wrd1 |= (((expon + 1023 - 1) & 0x7ff) << 20) | (tmp & 0xfffff);
*wrd2 = (uae_u32) (frac * 9007199254740992.0 - tmp * 4294967296.0);
}
static __inline__ double to_pack(uae_u32 wrd1, uae_u32 wrd2, uae_u32 wrd3)
{
double d;
char *cp;
char str[100];
cp = str;
if (wrd1 & 0x80000000)
*cp++ = '-';
*cp++ = (wrd1 & 0xf) + '0';
*cp++ = '.';
*cp++ = ((wrd2 >> 28) & 0xf) + '0';
*cp++ = ((wrd2 >> 24) & 0xf) + '0';
*cp++ = ((wrd2 >> 20) & 0xf) + '0';
*cp++ = ((wrd2 >> 16) & 0xf) + '0';
*cp++ = ((wrd2 >> 12) & 0xf) + '0';
*cp++ = ((wrd2 >> 8) & 0xf) + '0';
*cp++ = ((wrd2 >> 4) & 0xf) + '0';
*cp++ = ((wrd2 >> 0) & 0xf) + '0';
*cp++ = ((wrd3 >> 28) & 0xf) + '0';
*cp++ = ((wrd3 >> 24) & 0xf) + '0';
*cp++ = ((wrd3 >> 20) & 0xf) + '0';
*cp++ = ((wrd3 >> 16) & 0xf) + '0';
*cp++ = ((wrd3 >> 12) & 0xf) + '0';
*cp++ = ((wrd3 >> 8) & 0xf) + '0';
*cp++ = ((wrd3 >> 4) & 0xf) + '0';
*cp++ = ((wrd3 >> 0) & 0xf) + '0';
*cp++ = 'E';
if (wrd1 & 0x40000000)
*cp++ = '-';
*cp++ = ((wrd1 >> 24) & 0xf) + '0';
*cp++ = ((wrd1 >> 20) & 0xf) + '0';
*cp++ = ((wrd1 >> 16) & 0xf) + '0';
*cp = 0;
sscanf(str, "%le", &d);
return d;
}
static __inline__ void from_pack(double src, uae_u32 * wrd1, uae_u32 * wrd2, uae_u32 * wrd3)
{
int i;
int t;
char *cp;
char str[100];
sprintf(str, "%.16e", src);
cp = str;
*wrd1 = *wrd2 = *wrd3 = 0;
if (*cp == '-') {
cp++;
*wrd1 = 0x80000000;
}
if (*cp == '+')
cp++;
*wrd1 |= (*cp++ - '0');
if (*cp == '.')
cp++;
for (i = 0; i < 8; i++) {
*wrd2 <<= 4;
if (*cp >= '0' && *cp <= '9')
*wrd2 |= *cp++ - '0';
}
for (i = 0; i < 8; i++) {
*wrd3 <<= 4;
if (*cp >= '0' && *cp <= '9')
*wrd3 |= *cp++ - '0';
}
if (*cp == 'e' || *cp == 'E') {
cp++;
if (*cp == '-') {
cp++;
*wrd1 |= 0x40000000;
}
if (*cp == '+')
cp++;
t = 0;
for (i = 0; i < 3; i++) {
if (*cp >= '0' && *cp <= '9')
t = (t << 4) | (*cp++ - '0');
}
*wrd1 |= t << 16;
}
}
static __inline__ int get_fp_value(uae_u32 opcode, uae_u16 extra, double *src)
{
uaecptr tmppc;
uae_u16 tmp;
int size;
int mode;
int reg;
uae_u32 ad = 0;
static int sz1[8] =
{4, 4, 12, 12, 2, 8, 1, 0};
static int sz2[8] =
{4, 4, 12, 12, 2, 8, 2, 0};
if ((extra & 0x4000) == 0) {
*src = regs.fp[(extra >> 10) & 7];
return 1;
}
mode = (opcode >> 3) & 7;
reg = opcode & 7;
size = (extra >> 10) & 7;
switch (mode) {
case 0:
switch (size) {
case 6:
*src = (double) (uae_s8) m68k_dreg(regs, reg);
break;
case 4:
*src = (double) (uae_s16) m68k_dreg(regs, reg);
break;
case 0:
*src = (double) (uae_s32) m68k_dreg(regs, reg);
break;
case 1:
*src = to_single(m68k_dreg(regs, reg));
break;
default:
return 0;
}
return 1;
case 1:
return 0;
case 2:
ad = m68k_areg(regs, reg);
break;
case 3:
ad = m68k_areg(regs, reg);
m68k_areg(regs, reg) += reg == 7 ? sz2[size] : sz1[size];
break;
case 4:
m68k_areg(regs, reg) -= reg == 7 ? sz2[size] : sz1[size];
ad = m68k_areg(regs, reg);
break;
case 5:
ad = m68k_areg(regs, reg) + (uae_s32) (uae_s16) nextiword();
break;
case 6:
ad = get_disp_ea(m68k_areg(regs, reg), nextiword());
break;
case 7:
switch (reg) {
case 0:
ad = (uae_s32) (uae_s16) nextiword();
break;
case 1:
ad = nextilong();
break;
case 2:
ad = m68k_getpc();
ad += (uae_s32) (uae_s16) nextiword();
break;
case 3:
tmppc = m68k_getpc();
tmp = nextiword();
ad = get_disp_ea(tmppc, tmp);
break;
case 4:
ad = m68k_getpc();
m68k_setpc(ad + sz2[size]);
break;
default:
return 0;
}
}
switch (size) {
case 0:
*src = (double) (uae_s32) get_long(ad);
break;
case 1:
*src = to_single(get_long(ad));
break;
case 2:{
uae_u32 wrd1, wrd2, wrd3;
wrd1 = get_long(ad);
ad += 4;
wrd2 = get_long(ad);
ad += 4;
wrd3 = get_long(ad);
*src = to_exten(wrd1, wrd2, wrd3);
}
break;
case 3:{
uae_u32 wrd1, wrd2, wrd3;
wrd1 = get_long(ad);
ad += 4;
wrd2 = get_long(ad);
ad += 4;
wrd3 = get_long(ad);
*src = to_pack(wrd1, wrd2, wrd3);
}
break;
case 4:
*src = (double) (uae_s16) get_word(ad);
break;
case 5:{
uae_u32 wrd1, wrd2;
wrd1 = get_long(ad);
ad += 4;
wrd2 = get_long(ad);
*src = to_double(wrd1, wrd2);
}
break;
case 6:
*src = (double) (uae_s8) get_byte(ad);
break;
default:
return 0;
}
return 1;
}
static __inline__ int put_fp_value(double value, uae_u32 opcode, uae_u16 extra)
{
uae_u16 tmp;
uaecptr tmppc;
int size;
int mode;
int reg;
uae_u32 ad;
static int sz1[8] =
{4, 4, 12, 12, 2, 8, 1, 0};
static int sz2[8] =
{4, 4, 12, 12, 2, 8, 2, 0};
if ((extra & 0x4000) == 0) {
regs.fp[(extra >> 10) & 7] = value;
return 1;
}
mode = (opcode >> 3) & 7;
reg = opcode & 7;
size = (extra >> 10) & 7;
ad = -1;
switch (mode) {
case 0:
switch (size) {
case 6:
m68k_dreg(regs, reg) = (((int) value & 0xff)
| (m68k_dreg(regs, reg) & ~0xff));
break;
case 4:
m68k_dreg(regs, reg) = (((int) value & 0xffff)
| (m68k_dreg(regs, reg) & ~0xffff));
break;
case 0:
m68k_dreg(regs, reg) = (int) value;
break;
case 1:
m68k_dreg(regs, reg) = from_single(value);
break;
default:
return 0;
}
return 1;
case 1:
return 0;
case 2:
ad = m68k_areg(regs, reg);
break;
case 3:
ad = m68k_areg(regs, reg);
m68k_areg(regs, reg) += reg == 7 ? sz2[size] : sz1[size];
break;
case 4:
m68k_areg(regs, reg) -= reg == 7 ? sz2[size] : sz1[size];
ad = m68k_areg(regs, reg);
break;
case 5:
ad = m68k_areg(regs, reg) + (uae_s32) (uae_s16) nextiword();
break;
case 6:
ad = get_disp_ea(m68k_areg(regs, reg), nextiword());
break;
case 7:
switch (reg) {
case 0:
ad = (uae_s32) (uae_s16) nextiword();
break;
case 1:
ad = nextilong();
break;
case 2:
ad = m68k_getpc();
ad += (uae_s32) (uae_s16) nextiword();
break;
case 3:
tmppc = m68k_getpc();
tmp = nextiword();
ad = get_disp_ea(tmppc, tmp);
break;
case 4:
ad = m68k_getpc();
m68k_setpc(ad + sz2[size]);
break;
default:
return 0;
}
}
switch (size) {
case 0:
put_long(ad, (uae_s32) value);
break;
case 1:
put_long(ad, from_single(value));
break;
case 2:
{
uae_u32 wrd1, wrd2, wrd3;
from_exten(value, &wrd1, &wrd2, &wrd3);
put_long(ad, wrd1);
ad += 4;
put_long(ad, wrd2);
ad += 4;
put_long(ad, wrd3);
}
break;
case 3:
{
uae_u32 wrd1, wrd2, wrd3;
from_pack(value, &wrd1, &wrd2, &wrd3);
put_long(ad, wrd1);
ad += 4;
put_long(ad, wrd2);
ad += 4;
put_long(ad, wrd3);
}
break;
case 4:
put_word(ad, (uae_s16) value);
break;
case 5:{
uae_u32 wrd1, wrd2;
from_double(value, &wrd1, &wrd2);
put_long(ad, wrd1);
ad += 4;
put_long(ad, wrd2);
}
break;
case 6:
put_byte(ad, (uae_s8) value);
break;
default:
return 0;
}
return 1;
}
static __inline__ int get_fp_ad(uae_u32 opcode, uae_u32 * ad)
{
uae_u16 tmp;
uaecptr tmppc;
int mode;
int reg;
mode = (opcode >> 3) & 7;
reg = opcode & 7;
switch (mode) {
case 0:
case 1:
return 0;
case 2:
*ad = m68k_areg(regs, reg);
break;
case 3:
*ad = m68k_areg(regs, reg);
break;
case 4:
*ad = m68k_areg(regs, reg);
break;
case 5:
*ad = m68k_areg(regs, reg) + (uae_s32) (uae_s16) nextiword();
break;
case 6:
*ad = get_disp_ea(m68k_areg(regs, reg), nextiword());
break;
case 7:
switch (reg) {
case 0:
*ad = (uae_s32) (uae_s16) nextiword();
break;
case 1:
*ad = nextilong();
break;
case 2:
*ad = m68k_getpc();
*ad += (uae_s32) (uae_s16) nextiword();
break;
case 3:
tmppc = m68k_getpc();
tmp = nextiword();
*ad = get_disp_ea(tmppc, tmp);
break;
default:
return 0;
}
}
return 1;
}
static __inline__ int fpp_cond(uae_u32 opcode, int contition)
{
int N = (regs.fpsr & 0x8000000) != 0;
int Z = (regs.fpsr & 0x4000000) != 0;
/* int I = (regs.fpsr & 0x2000000) != 0; */
int NotANumber = (regs.fpsr & 0x1000000) != 0;
switch (contition) {
case 0x00:
return 0;
case 0x01:
return Z;
case 0x02:
return !(NotANumber || Z || N);
case 0x03:
return Z || !(NotANumber || N);
case 0x04:
return N && !(NotANumber || Z);
case 0x05:
return Z || (N && !NotANumber);
case 0x06:
return !(NotANumber || Z);
case 0x07:
return !NotANumber;
case 0x08:
return NotANumber;
case 0x09:
return NotANumber || Z;
case 0x0a:
return NotANumber || !(N || Z);
case 0x0b:
return NotANumber || Z || !N;
case 0x0c:
return NotANumber || (N && !Z);
case 0x0d:
return NotANumber || Z || N;
case 0x0e:
return !Z;
case 0x0f:
return 1;
case 0x10:
return 0;
case 0x11:
return Z;
case 0x12:
return !(NotANumber || Z || N);
case 0x13:
return Z || !(NotANumber || N);
case 0x14:
return N && !(NotANumber || Z);
case 0x15:
return Z || (N && !NotANumber);
case 0x16:
return !(NotANumber || Z);
case 0x17:
return !NotANumber;
case 0x18:
return NotANumber;
case 0x19:
return NotANumber || Z;
case 0x1a:
return NotANumber || !(N || Z);
case 0x1b:
return NotANumber || Z || !N;
case 0x1c:
return NotANumber || (Z && N);
case 0x1d:
return NotANumber || Z || N;
case 0x1e:
return !Z;
case 0x1f:
return 1;
}
return -1;
}
void fdbcc_opp(uae_u32 opcode, uae_u16 extra)
{
uaecptr pc = (uae_u32) m68k_getpc();
uae_s32 disp = (uae_s32) (uae_s16) nextiword();
int cc;
#if DEBUG_FPP
printf("fdbcc_opp at %08lx\n", m68k_getpc());
fflush(stdout);
#endif
cc = fpp_cond(opcode, extra & 0x3f);
if (cc == -1) {
m68k_setpc(pc - 4);
op_illg(opcode);
} else if (!cc) {
int reg = opcode & 0x7;
m68k_dreg(regs, reg) = ((m68k_dreg(regs, reg) & ~0xffff)
| ((m68k_dreg(regs, reg) - 1) & 0xffff));
if ((m68k_dreg(regs, reg) & 0xffff) == 0xffff)
m68k_setpc(pc + disp);
}
}
void fscc_opp(uae_u32 opcode, uae_u16 extra)
{
uae_u32 ad;
int cc;
#if DEBUG_FPP
printf("fscc_opp at %08lx\n", m68k_getpc());
fflush(stdout);
#endif
cc = fpp_cond(opcode, extra & 0x3f);
if (cc == -1) {
m68k_setpc(m68k_getpc() - 4);
op_illg(opcode);
} else if ((opcode & 0x38) == 0) {
m68k_dreg(regs, opcode & 7) = (m68k_dreg(regs, opcode & 7) & ~0xff) |
(cc ? 0xff : 0x00);
} else {
if (get_fp_ad(opcode, &ad) == 0) {
m68k_setpc(m68k_getpc() - 4);
op_illg(opcode);
} else
put_byte(ad, cc ? 0xff : 0x00);
}
}
void ftrapcc_opp(uae_u32 opcode, uaecptr oldpc)
{
int cc;
#if DEBUG_FPP
printf("ftrapcc_opp at %08lx\n", m68k_getpc());
fflush(stdout);
#endif
cc = fpp_cond(opcode, opcode & 0x3f);
if (cc == -1) {
m68k_setpc(oldpc);
op_illg(opcode);
}
if (cc)
Exception(7, oldpc - 2);
}
void fbcc_opp(uae_u32 opcode, uaecptr pc, uae_u32 extra)
{
int cc;
#if DEBUG_FPP
printf("fbcc_opp at %08lx\n", m68k_getpc());
fflush(stdout);
#endif
cc = fpp_cond(opcode, opcode & 0x3f);
if (cc == -1) {
m68k_setpc(pc);
op_illg(opcode);
} else if (cc) {
if ((opcode & 0x40) == 0)
extra = (uae_s32) (uae_s16) extra;
m68k_setpc(pc + extra);
}
}
void fsave_opp(uae_u32 opcode)
{
uae_u32 ad;
int incr = (opcode & 0x38) == 0x20 ? -1 : 1;
int i;
#if DEBUG_FPP
printf("fsave_opp at %08lx\n", m68k_getpc());
fflush(stdout);
#endif
if (get_fp_ad(opcode, &ad) == 0) {
m68k_setpc (m68k_getpc () - 2);
op_illg(opcode);
return;
}
if (incr < 0) {
ad -= 4;
put_long(ad, 0x70000000);
for (i = 0; i < 5; i++) {
ad -= 4;
put_long(ad, 0x00000000);
}
ad -= 4;
put_long(ad, 0x1f180000);
} else {
put_long(ad, 0x1f180000);
ad += 4;
for (i = 0; i < 5; i++) {
put_long(ad, 0x00000000);
ad += 4;
}
put_long(ad, 0x70000000);
ad += 4;
}
if ((opcode & 0x38) == 0x18)
m68k_areg(regs, opcode & 7) = ad;
if ((opcode & 0x38) == 0x20)
m68k_areg(regs, opcode & 7) = ad;
}
void frestore_opp(uae_u32 opcode)
{
uae_u32 ad;
uae_u32 d;
int incr = (opcode & 0x38) == 0x20 ? -1 : 1;
#if DEBUG_FPP
printf("frestore_opp at %08lx\n", m68k_getpc());
fflush(stdout);
#endif
if (get_fp_ad(opcode, &ad) == 0) {
m68k_setpc (m68k_getpc () - 2);
op_illg(opcode);
return;
}
if (incr < 0) {
ad -= 4;
d = get_long(ad);
if ((d & 0xff000000) != 0) {
if ((d & 0x00ff0000) == 0x00180000)
ad -= 6 * 4;
else if ((d & 0x00ff0000) == 0x00380000)
ad -= 14 * 4;
else if ((d & 0x00ff0000) == 0x00b40000)
ad -= 45 * 4;
}
} else {
d = get_long(ad);
ad += 4;
if ((d & 0xff000000) != 0) {
if ((d & 0x00ff0000) == 0x00180000)
ad += 6 * 4;
else if ((d & 0x00ff0000) == 0x00380000)
ad += 14 * 4;
else if ((d & 0x00ff0000) == 0x00b40000)
ad += 45 * 4;
}
}
if ((opcode & 0x38) == 0x18)
m68k_areg(regs, opcode & 7) = ad;
if ((opcode & 0x38) == 0x20)
m68k_areg(regs, opcode & 7) = ad;
}
void fpp_opp(uae_u32 opcode, uae_u16 extra)
{
int reg;
double src;
#if DEBUG_FPP
printf("FPP %04lx %04x at %08lx\n", opcode & 0xffff, extra & 0xffff,
m68k_getpc() - 4);
fflush(stdout);
#endif
switch ((extra >> 13) & 0x7) {
case 3:
if (put_fp_value(regs.fp[(extra >> 7) & 7], opcode, extra) == 0) {
m68k_setpc(m68k_getpc() - 4);
op_illg(opcode);
}
return;
case 4:
case 5:
if ((opcode & 0x38) == 0) {
if (extra & 0x2000) {
if (extra & 0x1000)
m68k_dreg(regs, opcode & 7) = regs.fpcr;
if (extra & 0x0800)
m68k_dreg(regs, opcode & 7) = regs.fpsr;
if (extra & 0x0400)
m68k_dreg(regs, opcode & 7) = regs.fpiar;
} else {
if (extra & 0x1000)
regs.fpcr = m68k_dreg(regs, opcode & 7);
if (extra & 0x0800)
regs.fpsr = m68k_dreg(regs, opcode & 7);
if (extra & 0x0400)
regs.fpiar = m68k_dreg(regs, opcode & 7);
}
} else if ((opcode & 0x38) == 1) {
if (extra & 0x2000) {
if (extra & 0x1000)
m68k_areg(regs, opcode & 7) = regs.fpcr;
if (extra & 0x0800)
m68k_areg(regs, opcode & 7) = regs.fpsr;
if (extra & 0x0400)
m68k_areg(regs, opcode & 7) = regs.fpiar;
} else {
if (extra & 0x1000)
regs.fpcr = m68k_areg(regs, opcode & 7);
if (extra & 0x0800)
regs.fpsr = m68k_areg(regs, opcode & 7);
if (extra & 0x0400)
regs.fpiar = m68k_areg(regs, opcode & 7);
}
} else if ((opcode & 0x3f) == 0x3c) {
if ((extra & 0x2000) == 0) {
if (extra & 0x1000)
regs.fpcr = nextilong();
if (extra & 0x0800)
regs.fpsr = nextilong();
if (extra & 0x0400)
regs.fpiar = nextilong();
}
} else if (extra & 0x2000) {
/* FMOVEM FPP->memory */
uae_u32 ad;
int incr = 0;
if (get_fp_ad(opcode, &ad) == 0) {
m68k_setpc(m68k_getpc() - 4);
op_illg(opcode);
return;
}
if ((opcode & 0x38) == 0x20) {
if (extra & 0x1000)
incr += 4;
if (extra & 0x0800)
incr += 4;
if (extra & 0x0400)
incr += 4;
}
ad -= incr;
if (extra & 0x1000) {
put_long(ad, regs.fpcr);
ad += 4;
}
if (extra & 0x0800) {
put_long(ad, regs.fpsr);
ad += 4;
}
if (extra & 0x0400) {
put_long(ad, regs.fpiar);
ad += 4;
}
ad -= incr;
if ((opcode & 0x38) == 0x18)
m68k_areg(regs, opcode & 7) = ad;
if ((opcode & 0x38) == 0x20)
m68k_areg(regs, opcode & 7) = ad;
} else {
/* FMOVEM memory->FPP */
uae_u32 ad;
if (get_fp_ad(opcode, &ad) == 0) {
m68k_setpc(m68k_getpc() - 4);
op_illg(opcode);
return;
}
ad = (opcode & 0x38) == 0x20 ? ad - 12 : ad;
if (extra & 0x1000) {
regs.fpcr = get_long(ad);
ad += 4;
}
if (extra & 0x0800) {
regs.fpsr = get_long(ad);
ad += 4;
}
if (extra & 0x0400) {
regs.fpiar = get_long(ad);
ad += 4;
}
if ((opcode & 0x38) == 0x18)
m68k_areg(regs, opcode & 7) = ad;
if ((opcode & 0x38) == 0x20)
m68k_areg(regs, opcode & 7) = ad - 12;
}
return;
case 6:
case 7:
{
uae_u32 ad, list = 0;
int incr = 0;
if (extra & 0x2000) {
/* FMOVEM FPP->memory */
if (get_fp_ad(opcode, &ad) == 0) {
m68k_setpc(m68k_getpc() - 4);
op_illg(opcode);
return;
}
switch ((extra >> 11) & 3) {
case 0: /* static pred */
list = extra & 0xff;
incr = -1;
break;
case 1: /* dynamic pred */
list = m68k_dreg(regs, (extra >> 4) & 3) & 0xff;
incr = -1;
break;
case 2: /* static postinc */
list = extra & 0xff;
incr = 1;
break;
case 3: /* dynamic postinc */
list = m68k_dreg(regs, (extra >> 4) & 3) & 0xff;
incr = 1;
break;
}
while (list) {
uae_u32 wrd1, wrd2, wrd3;
if (incr < 0) {
from_exten(
regs.fp[fpp_movem_index2[list]],
&wrd1, &wrd2, &wrd3);
ad -= 4;
put_long(ad, wrd3);
ad -= 4;
put_long(ad, wrd2);
ad -= 4;
put_long(ad, wrd1);
} else {
from_exten(
regs.fp[fpp_movem_index1[list]],
&wrd1, &wrd2, &wrd3);
put_long(ad, wrd1);
ad += 4;
put_long(ad, wrd2);
ad += 4;
put_long(ad, wrd3);
ad += 4;
}
list = fpp_movem_next[list];
}
if ((opcode & 0x38) == 0x18)
m68k_areg(regs, opcode & 7) = ad;
if ((opcode & 0x38) == 0x20)
m68k_areg(regs, opcode & 7) = ad;
} else {
/* FMOVEM memory->FPP */
if (get_fp_ad(opcode, &ad) == 0) {
m68k_setpc(m68k_getpc() - 4);
op_illg(opcode);
return;
}
switch ((extra >> 11) & 3) {
case 0: /* static pred */
list = extra & 0xff;
incr = -1;
break;
case 1: /* dynamic pred */
list = m68k_dreg(regs, (extra >> 4) & 3) & 0xff;
incr = -1;
break;
case 2: /* static postinc */
list = extra & 0xff;
incr = 1;
break;
case 3: /* dynamic postinc */
list = m68k_dreg(regs, (extra >> 4) & 3) & 0xff;
incr = 1;
break;
}
while (list) {
uae_u32 wrd1, wrd2, wrd3;
if (incr < 0) {
ad -= 4;
wrd3 = get_long(ad);
ad -= 4;
wrd2 = get_long(ad);
ad -= 4;
wrd1 = get_long(ad);
regs.fp[fpp_movem_index2[list]] =
to_exten(wrd1, wrd2, wrd3);
} else {
wrd1 = get_long(ad);
ad += 4;
wrd2 = get_long(ad);
ad += 4;
wrd3 = get_long(ad);
ad += 4;
regs.fp[fpp_movem_index1[list]] =
to_exten(wrd1, wrd2, wrd3);
}
list = fpp_movem_next[list];
}
if ((opcode & 0x38) == 0x18)
m68k_areg(regs, opcode & 7) = ad;
if ((opcode & 0x38) == 0x20)
m68k_areg(regs, opcode & 7) = ad;
}
}
return;
case 0:
case 2:
reg = (extra >> 7) & 7;
if ((extra & 0xfc00) == 0x5c00) {
switch (extra & 0x7f) {
case 0x00:
regs.fp[reg] = 4.0 * atan(1.0);
break;
case 0x0b:
regs.fp[reg] = log10(2.0);
break;
case 0x0c:
regs.fp[reg] = exp(1.0);
break;
case 0x0d:
regs.fp[reg] = log(exp(1.0)) / log(2.0);
break;
case 0x0e:
regs.fp[reg] = log(exp(1.0)) / log(10.0);
break;
case 0x0f:
regs.fp[reg] = 0.0;
break;
case 0x30:
regs.fp[reg] = log(2.0);
break;
case 0x31:
regs.fp[reg] = log(10.0);
break;
case 0x32:
regs.fp[reg] = 1.0e0;
break;
case 0x33:
regs.fp[reg] = 1.0e1;
break;
case 0x34:
regs.fp[reg] = 1.0e2;
break;
case 0x35:
regs.fp[reg] = 1.0e4;
break;
case 0x36:
regs.fp[reg] = 1.0e8;
break;
case 0x37:
regs.fp[reg] = 1.0e16;
break;
case 0x38:
regs.fp[reg] = 1.0e32;
break;
case 0x39:
regs.fp[reg] = 1.0e64;
break;
case 0x3a:
regs.fp[reg] = 1.0e128;
break;
case 0x3b:
regs.fp[reg] = 1.0e256;
break;
#if 0
case 0x3c:
regs.fp[reg] = 1.0e512;
break;
case 0x3d:
regs.fp[reg] = 1.0e1024;
break;
case 0x3e:
regs.fp[reg] = 1.0e2048;
break;
case 0x3f:
regs.fp[reg] = 1.0e4096;
break;
#endif
default:
m68k_setpc(m68k_getpc() - 4);
op_illg(opcode);
break;
}
return;
}
if (get_fp_value(opcode, extra, &src) == 0) {
m68k_setpc(m68k_getpc() - 4);
op_illg(opcode);
return;
}
switch (extra & 0x7f) {
case 0x00: /* FMOVE */
regs.fp[reg] = src;
break;
case 0x01: /* FINT */
regs.fp[reg] = (int) (src + 0.5);
regs.fpsr = (regs.fp[reg] == 0 ? 0x4000000 : 0) |
(regs.fp[reg] < 0 ? 0x8000000 : 0);
break;
case 0x02: /* FSINH */
regs.fp[reg] = sinh(src);
regs.fpsr = (regs.fp[reg] == 0 ? 0x4000000 : 0) |
(regs.fp[reg] < 0 ? 0x8000000 : 0);
break;
case 0x03: /* FINTRZ */
regs.fp[reg] = (int) src;
regs.fpsr = (regs.fp[reg] == 0 ? 0x4000000 : 0) |
(regs.fp[reg] < 0 ? 0x8000000 : 0);
break;
case 0x04: /* FSQRT */
regs.fp[reg] = sqrt(src);
regs.fpsr = (regs.fp[reg] == 0 ? 0x4000000 : 0) |
(regs.fp[reg] < 0 ? 0x8000000 : 0);
break;
case 0x06: /* FLOGNP1 */
regs.fp[reg] = log(src + 1.0);
regs.fpsr = (regs.fp[reg] == 0 ? 0x4000000 : 0) |
(regs.fp[reg] < 0 ? 0x8000000 : 0);
break;
case 0x08: /* FETOXM1 */
regs.fp[reg] = exp(src) - 1.0;
regs.fpsr = (regs.fp[reg] == 0 ? 0x4000000 : 0) |
(regs.fp[reg] < 0 ? 0x8000000 : 0);
break;
case 0x09: /* FTANH */
regs.fp[reg] = tanh(src);
regs.fpsr = (regs.fp[reg] == 0 ? 0x4000000 : 0) |
(regs.fp[reg] < 0 ? 0x8000000 : 0);
break;
case 0x0a: /* FATAN */
regs.fp[reg] = atan(src);
regs.fpsr = (regs.fp[reg] == 0 ? 0x4000000 : 0) |
(regs.fp[reg] < 0 ? 0x8000000 : 0);
break;
case 0x0c: /* FASIN */
regs.fp[reg] = asin(src);
regs.fpsr = (regs.fp[reg] == 0 ? 0x4000000 : 0) |
(regs.fp[reg] < 0 ? 0x8000000 : 0);
break;
case 0x0d: /* FATANH */
#if 1 /* The BeBox doesn't have atanh, and it isn't in the HPUX libm either */
regs.fp[reg] = log((1 + src) / (1 - src)) / 2;
#else
regs.fp[reg] = atanh(src);
#endif
regs.fpsr = (regs.fp[reg] == 0 ? 0x4000000 : 0) |
(regs.fp[reg] < 0 ? 0x8000000 : 0);
break;
case 0x0e: /* FSIN */
regs.fp[reg] = sin(src);
regs.fpsr = (regs.fp[reg] == 0 ? 0x4000000 : 0) |
(regs.fp[reg] < 0 ? 0x8000000 : 0);
break;
case 0x0f: /* FTAN */
regs.fp[reg] = tan(src);
regs.fpsr = (regs.fp[reg] == 0 ? 0x4000000 : 0) |
(regs.fp[reg] < 0 ? 0x8000000 : 0);
break;
case 0x10: /* FETOX */
regs.fp[reg] = exp(src);
regs.fpsr = (regs.fp[reg] == 0 ? 0x4000000 : 0) |
(regs.fp[reg] < 0 ? 0x8000000 : 0);
break;
case 0x11: /* FTWOTOX */
regs.fp[reg] = pow(2.0, src);
regs.fpsr = (regs.fp[reg] == 0 ? 0x4000000 : 0) |
(regs.fp[reg] < 0 ? 0x8000000 : 0);
break;
case 0x12: /* FTENTOX */
regs.fp[reg] = pow(10.0, src);
regs.fpsr = (regs.fp[reg] == 0 ? 0x4000000 : 0) |
(regs.fp[reg] < 0 ? 0x8000000 : 0);
break;
case 0x14: /* FLOGN */
regs.fp[reg] = log(src);
regs.fpsr = (regs.fp[reg] == 0 ? 0x4000000 : 0) |
(regs.fp[reg] < 0 ? 0x8000000 : 0);
break;
case 0x15: /* FLOG10 */
regs.fp[reg] = log10(src);
regs.fpsr = (regs.fp[reg] == 0 ? 0x4000000 : 0) |
(regs.fp[reg] < 0 ? 0x8000000 : 0);
break;
case 0x16: /* FLOG2 */
regs.fp[reg] = log(src) / log(2.0);
regs.fpsr = (regs.fp[reg] == 0 ? 0x4000000 : 0) |
(regs.fp[reg] < 0 ? 0x8000000 : 0);
break;
case 0x18: /* FABS */
regs.fp[reg] = src < 0 ? -src : src;
regs.fpsr = (regs.fp[reg] == 0 ? 0x4000000 : 0) |
(regs.fp[reg] < 0 ? 0x8000000 : 0);
break;
case 0x19: /* FCOSH */
regs.fp[reg] = cosh(src);
regs.fpsr = (regs.fp[reg] == 0 ? 0x4000000 : 0) |
(regs.fp[reg] < 0 ? 0x8000000 : 0);
break;
case 0x1a: /* FNEG */
regs.fp[reg] = -src;
regs.fpsr = (regs.fp[reg] == 0 ? 0x4000000 : 0) |
(regs.fp[reg] < 0 ? 0x8000000 : 0);
break;
case 0x1c: /* FACOS */
regs.fp[reg] = acos(src);
regs.fpsr = (regs.fp[reg] == 0 ? 0x4000000 : 0) |
(regs.fp[reg] < 0 ? 0x8000000 : 0);
break;
case 0x1d: /* FCOS */
regs.fp[reg] = cos(src);
regs.fpsr = (regs.fp[reg] == 0 ? 0x4000000 : 0) |
(regs.fp[reg] < 0 ? 0x8000000 : 0);
break;
case 0x1e: /* FGETEXP */
{
int expon;
frexp(src, &expon);
regs.fp[reg] = (double) (expon - 1);
regs.fpsr = (regs.fp[reg] == 0 ? 0x4000000 : 0) |
(regs.fp[reg] < 0 ? 0x8000000 : 0);
}
break;
case 0x1f: /* FGETMAN */
{
int expon;
regs.fp[reg] = frexp(src, &expon) * 2.0;
regs.fpsr = (regs.fp[reg] == 0 ? 0x4000000 : 0) |
(regs.fp[reg] < 0 ? 0x8000000 : 0);
}
break;
case 0x20: /* FDIV */
regs.fp[reg] /= src;
regs.fpsr = (regs.fp[reg] == 0 ? 0x4000000 : 0) |
(regs.fp[reg] < 0 ? 0x8000000 : 0);
break;
case 0x21: /* FMOD */
regs.fp[reg] = regs.fp[reg] -
(double) ((int) (regs.fp[reg] / src)) * src;
regs.fpsr = (regs.fp[reg] == 0 ? 0x4000000 : 0) |
(regs.fp[reg] < 0 ? 0x8000000 : 0);
break;
case 0x22: /* FADD */
regs.fp[reg] += src;
regs.fpsr = (regs.fp[reg] == 0 ? 0x4000000 : 0) |
(regs.fp[reg] < 0 ? 0x8000000 : 0);
break;
case 0x23: /* FMUL */
regs.fp[reg] *= src;
regs.fpsr = (regs.fp[reg] == 0 ? 0x4000000 : 0) |
(regs.fp[reg] < 0 ? 0x8000000 : 0);
break;
case 0x24: /* FSGLDIV */
regs.fp[reg] /= src;
regs.fpsr = (regs.fp[reg] == 0 ? 0x4000000 : 0) |
(regs.fp[reg] < 0 ? 0x8000000 : 0);
break;
case 0x25: /* FREM */
regs.fp[reg] = regs.fp[reg] -
(double) ((int) (regs.fp[reg] / src + 0.5)) * src;
regs.fpsr = (regs.fp[reg] == 0 ? 0x4000000 : 0) |
(regs.fp[reg] < 0 ? 0x8000000 : 0);
break;
case 0x26: /* FSCALE */
regs.fp[reg] *= exp(log(2.0) * src);
regs.fpsr = (regs.fp[reg] == 0 ? 0x4000000 : 0) |
(regs.fp[reg] < 0 ? 0x8000000 : 0);
break;
case 0x27: /* FSGLMUL */
regs.fp[reg] *= src;
regs.fpsr = (regs.fp[reg] == 0 ? 0x4000000 : 0) |
(regs.fp[reg] < 0 ? 0x8000000 : 0);
break;
case 0x28: /* FSUB */
regs.fp[reg] -= src;
regs.fpsr = (regs.fp[reg] == 0 ? 0x4000000 : 0) |
(regs.fp[reg] < 0 ? 0x8000000 : 0);
break;
case 0x30: /* FSINCOS */
case 0x31:
case 0x32:
case 0x33:
case 0x34:
case 0x35:
case 0x36:
case 0x37:
regs.fp[reg] = sin(src);
regs.fp[extra & 7] = cos(src);
regs.fpsr = (regs.fp[reg] == 0 ? 0x4000000 : 0) |
(regs.fp[reg] < 0 ? 0x8000000 : 0);
break;
case 0x38: /* FCMP */
{
double tmp = regs.fp[reg] - src;
regs.fpsr = (tmp == 0 ? 0x4000000 : 0) |
(tmp < 0 ? 0x8000000 : 0);
}
break;
case 0x3a: /* FTST */
regs.fpsr = (src == 0 ? 0x4000000 : 0) |
(src < 0 ? 0x8000000 : 0);
break;
default:
m68k_setpc(m68k_getpc() - 4);
op_illg(opcode);
break;
}
return;
}
m68k_setpc(m68k_getpc() - 4);
op_illg(opcode);
}
#endif